{
struct domain *d = v->domain;
struct paging_mode *old_mode = v->arch.paging.mode;
- mfn_t old_guest_table;
ASSERT(shadow_locked_by_me(d));
#else
#error unexpected paging mode
#endif
- v->arch.paging.translate_enabled = !!shadow_mode_translate(d);
}
else
{
ASSERT(shadow_mode_translate(d));
ASSERT(shadow_mode_external(d));
- v->arch.paging.translate_enabled = hvm_paging_enabled(v);
- if ( !v->arch.paging.translate_enabled )
+ if ( !hvm_paging_enabled(v) )
{
- /* Set v->arch.guest_table to use the p2m map, and choose
- * the appropriate shadow mode */
- old_guest_table = pagetable_get_mfn(v->arch.guest_table);
-#if CONFIG_PAGING_LEVELS == 2
- v->arch.guest_table =
- pagetable_from_pfn(pagetable_get_pfn(d->arch.phys_table));
- v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,2,2);
-#elif CONFIG_PAGING_LEVELS == 3
- v->arch.guest_table =
- pagetable_from_pfn(pagetable_get_pfn(d->arch.phys_table));
- v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,3,3);
-#else /* CONFIG_PAGING_LEVELS == 4 */
- {
- l4_pgentry_t *l4e;
- /* Use the start of the first l3 table as a PAE l3 */
- ASSERT(pagetable_get_pfn(d->arch.phys_table) != 0);
- l4e = sh_map_domain_page(pagetable_get_mfn(d->arch.phys_table));
- ASSERT(l4e_get_flags(l4e[0]) & _PAGE_PRESENT);
- v->arch.guest_table =
- pagetable_from_pfn(l4e_get_pfn(l4e[0]));
- sh_unmap_domain_page(l4e);
- }
- v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,3,3);
+ /* When the guest has CR0.PG clear, we provide a 32-bit, non-PAE
+ * pagetable for it, mapping 4 GB one-to-one using a single l2
+ * page of 1024 superpage mappings */
+ v->arch.guest_table = d->arch.paging.shadow.unpaged_pagetable;
+#if CONFIG_PAGING_LEVELS >= 3
+ v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode, 3, 2);
+#else
+ v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode, 2, 2);
#endif
- /* Fix up refcounts on guest_table */
- get_page(mfn_to_page(pagetable_get_mfn(v->arch.guest_table)), d);
- if ( mfn_x(old_guest_table) != 0 )
- put_page(mfn_to_page(old_guest_table));
}
else
{
* Returns 0 for success, -errno for failure. */
{
unsigned int old_pages;
- int rv = 0;
+ struct page_info *pg = NULL;
+ uint32_t *e;
+ int i, rv = 0;
mode |= PG_SH_enable;
goto out_unlocked;
}
+ /* HVM domains need an extra pagetable for vcpus that think they
+ * have paging disabled */
+ if ( is_hvm_domain(d) )
+ {
+ /* Get a single page from the shadow pool. Take it via the
+ * P2M interface to make freeing it simpler afterwards. */
+ pg = shadow_alloc_p2m_page(d);
+ if ( pg == NULL )
+ {
+ rv = -ENOMEM;
+ goto out_unlocked;
+ }
+ /* Fill it with 32-bit, non-PAE superpage entries, each mapping 4MB
+ * of virtual address space onto the same physical address range */
+ e = sh_map_domain_page(page_to_mfn(pg));
+ for ( i = 0; i < PAGE_SIZE / sizeof(*e); i++ )
+ e[i] = ((0x400000U * i)
+ | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER
+ | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE);
+ sh_unmap_domain_page(e);
+ pg->u.inuse.type_info = PGT_l2_page_table | 1 | PGT_validated;
+ }
shadow_lock(d);
d->arch.paging.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL;
#endif
+ /* Record the 1-to-1 pagetable we just made */
+ if ( is_hvm_domain(d) )
+ d->arch.paging.shadow.unpaged_pagetable = pagetable_from_page(pg);
+
/* Update the bits */
sh_new_mode(d, mode);
out_unlocked:
if ( rv != 0 && !pagetable_is_null(d->arch.phys_table) )
p2m_teardown(d);
+ if ( rv != 0 && pg != NULL )
+ shadow_free_p2m_page(d, pg);
domain_unpause(d);
return rv;
}
ASSERT(d->arch.paging.shadow.total_pages == 0);
}
+ /* Free the non-paged-vcpus pagetable; must happen after we've
+ * destroyed any shadows of it or sh_destroy_shadow will get confused. */
+ if ( !pagetable_is_null(d->arch.paging.shadow.unpaged_pagetable) )
+ {
+ for_each_vcpu(d, v)
+ {
+ ASSERT(is_hvm_vcpu(v));
+ if ( !hvm_paging_enabled(v) )
+ v->arch.guest_table = pagetable_null();
+ }
+ shadow_free_p2m_page(d,
+ pagetable_get_page(d->arch.paging.shadow.unpaged_pagetable));
+ d->arch.paging.shadow.unpaged_pagetable = pagetable_null();
+ }
+
/* We leave the "permanent" shadow modes enabled, but clear the
* log-dirty mode bit. We don't want any more mark_dirty()
* calls now that we've torn down the bitmap */
/* update the entry with new content */
safe_write_pte(p, new);
- /* The P2M can be shadowed: keep the shadows synced */
- if ( d->vcpu[0] != NULL )
- (void)sh_validate_guest_entry(d->vcpu[0], table_mfn, p, sizeof(*p));
-
/* install P2M in monitors for PAE Xen */
#if CONFIG_PAGING_LEVELS == 3
if ( level == 3 ) {
guest_supports_superpages(struct vcpu *v)
{
/* The _PAGE_PSE bit must be honoured in HVM guests, whenever
- * CR4.PSE is set or the guest is in PAE or long mode */
- return (is_hvm_vcpu(v) && (GUEST_PAGING_LEVELS != 2
- || (v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PSE)));
+ * CR4.PSE is set or the guest is in PAE or long mode.
+ * It's also used in the dummy PT for vcpus with CR4.PG cleared. */
+ return (is_hvm_vcpu(v) &&
+ (GUEST_PAGING_LEVELS != 2
+ || !hvm_paging_enabled(v)
+ || (v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PSE)));
}
static inline int
static inline int
guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op)
{
- ASSERT(!guest_op || shadow_locked_by_me(v->domain));
-
+ struct domain *d = v->domain;
+ ASSERT(!guest_op || shadow_locked_by_me(d));
+
perfc_incr(shadow_guest_walk);
memset(gw, 0, sizeof(*gw));
gw->va = va;
+ guest_l4_table_offset(va);
/* Walk down to the l3e */
if ( !(guest_l4e_get_flags(*gw->l4e) & _PAGE_PRESENT) ) return 0;
- gw->l3mfn = vcpu_gfn_to_mfn(v, guest_l4e_get_gfn(*gw->l4e));
+ gw->l3mfn = gfn_to_mfn(d, guest_l4e_get_gfn(*gw->l4e));
if ( !mfn_valid(gw->l3mfn) ) return 1;
/* This mfn is a pagetable: make sure the guest can't write to it. */
if ( guest_op && sh_remove_write_access(v, gw->l3mfn, 3, va) != 0 )
- flush_tlb_mask(v->domain->domain_dirty_cpumask);
+ flush_tlb_mask(d->domain_dirty_cpumask);
gw->l3e = ((guest_l3e_t *)sh_map_domain_page(gw->l3mfn))
+ guest_l3_table_offset(va);
#else /* PAE only... */
#endif /* PAE or 64... */
/* Walk down to the l2e */
if ( !(guest_l3e_get_flags(*gw->l3e) & _PAGE_PRESENT) ) return 0;
- gw->l2mfn = vcpu_gfn_to_mfn(v, guest_l3e_get_gfn(*gw->l3e));
+ gw->l2mfn = gfn_to_mfn(d, guest_l3e_get_gfn(*gw->l3e));
if ( !mfn_valid(gw->l2mfn) ) return 1;
/* This mfn is a pagetable: make sure the guest can't write to it. */
if ( guest_op && sh_remove_write_access(v, gw->l2mfn, 2, va) != 0 )
- flush_tlb_mask(v->domain->domain_dirty_cpumask);
+ flush_tlb_mask(d->domain_dirty_cpumask);
gw->l2e = ((guest_l2e_t *)sh_map_domain_page(gw->l2mfn))
+ guest_l2_table_offset(va);
#else /* 32-bit only... */
else
{
/* Not a superpage: carry on and find the l1e. */
- gw->l1mfn = vcpu_gfn_to_mfn(v, guest_l2e_get_gfn(*gw->l2e));
+ gw->l1mfn = gfn_to_mfn(d, guest_l2e_get_gfn(*gw->l2e));
if ( !mfn_valid(gw->l1mfn) ) return 1;
/* This mfn is a pagetable: make sure the guest can't write to it. */
if ( guest_op
&& sh_remove_write_access(v, gw->l1mfn, 1, va) != 0 )
- flush_tlb_mask(v->domain->domain_dirty_cpumask);
+ flush_tlb_mask(d->domain_dirty_cpumask);
gw->l1e = ((guest_l1e_t *)sh_map_domain_page(gw->l1mfn))
+ guest_l1_table_offset(va);
gw->eff_l1e = *gw->l1e;
guest_l4e_t *new_gl4e = new_ge;
shadow_l4e_t *sl4p = se;
mfn_t sl3mfn = _mfn(INVALID_MFN);
+ struct domain *d = v->domain;
int result = 0;
perfc_incr(shadow_validate_gl4e_calls);
if ( guest_l4e_get_flags(*new_gl4e) & _PAGE_PRESENT )
{
gfn_t gl3gfn = guest_l4e_get_gfn(*new_gl4e);
- mfn_t gl3mfn = vcpu_gfn_to_mfn(v, gl3gfn);
+ mfn_t gl3mfn = gfn_to_mfn(d, gl3gfn);
if ( mfn_valid(gl3mfn) )
sl3mfn = get_shadow_status(v, gl3mfn, SH_type_l3_shadow);
else
sl3mfn, &new_sl4e, ft_prefetch);
// check for updates to xen reserved slots
- if ( !shadow_mode_external(v->domain) )
+ if ( !shadow_mode_external(d) )
{
int shadow_index = (((unsigned long)sl4p & ~PAGE_MASK) /
sizeof(shadow_l4e_t));
- int reserved_xen_slot = !is_guest_l4_slot(v->domain, shadow_index);
+ int reserved_xen_slot = !is_guest_l4_slot(d, shadow_index);
if ( unlikely(reserved_xen_slot) )
{
if ( guest_l3e_get_flags(*new_gl3e) & _PAGE_PRESENT )
{
gfn_t gl2gfn = guest_l3e_get_gfn(*new_gl3e);
- mfn_t gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
+ mfn_t gl2mfn = gfn_to_mfn(v->domain, gl2gfn);
if ( mfn_valid(gl2mfn) )
sl2mfn = get_shadow_status(v, gl2mfn, SH_type_l2_shadow);
else
}
else
{
- mfn_t gl1mfn = vcpu_gfn_to_mfn(v, gl1gfn);
+ mfn_t gl1mfn = gfn_to_mfn(v->domain, gl1gfn);
if ( mfn_valid(gl1mfn) )
sl1mfn = get_shadow_status(v, gl1mfn, SH_type_l1_shadow);
else
perfc_incr(shadow_validate_gl1e_calls);
gfn = guest_l1e_get_gfn(*new_gl1e);
- gmfn = vcpu_gfn_to_mfn(v, gfn);
+ gmfn = gfn_to_mfn(v->domain, gfn);
- mmio = (is_hvm_vcpu(v) && paging_vcpu_mode_translate(v) &&
- mmio_space(gfn_to_paddr(gfn)));
+ mmio = (is_hvm_vcpu(v) && mmio_space(gfn_to_paddr(gfn)));
l1e_propagate_from_guest(v, new_gl1e, _mfn(INVALID_MFN), gmfn, &new_sl1e,
ft_prefetch, mmio);
/* Look at the gfn that the l1e is pointing at */
gfn = guest_l1e_get_gfn(gl1e);
- gmfn = vcpu_gfn_to_mfn(v, gfn);
- mmio = ( is_hvm_vcpu(v)
- && paging_vcpu_mode_translate(v)
- && mmio_space(gfn_to_paddr(gfn)) );
+ gmfn = gfn_to_mfn(v->domain, gfn);
+ mmio = ( is_hvm_vcpu(v) && mmio_space(gfn_to_paddr(gfn)) );
/* Propagate the entry. Safe to use a pointer to our local
* gl1e, since this is not a demand-fetch so there will be no
{
if ( sh_l1e_is_gnp(sl1e) )
{
- if ( likely(!is_hvm_domain(d) ||
- paging_vcpu_mode_translate(v)) )
- {
- /* Not-present in a guest PT: pass to the guest as
- * a not-present fault (by flipping two bits). */
- ASSERT(regs->error_code & PFEC_page_present);
- regs->error_code ^= (PFEC_reserved_bit|PFEC_page_present);
- reset_early_unshadow(v);
- perfc_incr(shadow_fault_fast_gnp);
- SHADOW_PRINTK("fast path not-present\n");
- return 0;
- }
- else
- {
- /* Not-present in the P2M: MMIO */
- gpa = va;
- }
+ /* Not-present in a guest PT: pass to the guest as
+ * a not-present fault (by flipping two bits). */
+ ASSERT(regs->error_code & PFEC_page_present);
+ regs->error_code ^= (PFEC_reserved_bit|PFEC_page_present);
+ reset_early_unshadow(v);
+ perfc_incr(shadow_fault_fast_gnp);
+ SHADOW_PRINTK("fast path not-present\n");
+ return 0;
}
else
{
//
if ( unlikely(!(guest_l1e_get_flags(gw.eff_l1e) & _PAGE_PRESENT)) )
{
- if ( is_hvm_domain(d) && !paging_vcpu_mode_translate(v) )
- {
- /* Not present in p2m map, means this is mmio */
- gpa = va;
- goto mmio;
- }
-
perfc_incr(shadow_fault_bail_not_present);
goto not_a_shadow_fault;
}
/* What mfn is the guest trying to access? */
gfn = guest_l1e_get_gfn(gw.eff_l1e);
- gmfn = vcpu_gfn_to_mfn(v, gfn);
- mmio = (is_hvm_domain(d)
- && paging_vcpu_mode_translate(v)
- && mmio_space(gfn_to_paddr(gfn)));
+ gmfn = gfn_to_mfn(d, gfn);
+ mmio = (is_hvm_domain(d) && mmio_space(gfn_to_paddr(gfn)));
if ( !mmio && !mfn_valid(gmfn) )
{
ASSERT(shadow_mode_external(d));
// Is paging enabled on this vcpu?
- if ( paging_vcpu_mode_translate(v) )
+ if ( hvm_paging_enabled(v) )
{
gfn = _gfn(paddr_to_pfn(v->arch.hvm_vcpu.guest_cr[3]));
- gmfn = vcpu_gfn_to_mfn(v, gfn);
+ gmfn = gfn_to_mfn(d, gfn);
ASSERT(mfn_valid(gmfn));
ASSERT(pagetable_get_pfn(v->arch.guest_table) == mfn_x(gmfn));
}
else
{
- /* Paging disabled: guest_table points at (part of) p2m */
-#if SHADOW_PAGING_LEVELS != 3 /* in 3-on-4, guest-table is in slot 0 of p2m */
- /* For everything else, they sould be the same */
- ASSERT(v->arch.guest_table.pfn == d->arch.phys_table.pfn);
-#endif
+ /* Paging disabled: guest_table points at a 32-bit 1-to-1 map */
+ ASSERT(v->arch.guest_table.pfn
+ == d->arch.paging.shadow.unpaged_pagetable.pfn);
}
}
#endif
* until the next CR3 write makes us refresh our cache. */
ASSERT(v->arch.paging.shadow.guest_vtable == NULL);
- if ( shadow_mode_external(d) && paging_vcpu_mode_translate(v) )
- /* Paging enabled: find where in the page the l3 table is */
+ if ( shadow_mode_external(d) )
+ /* Find where in the page the l3 table is */
guest_idx = guest_index((void *)v->arch.hvm_vcpu.guest_cr[3]);
else
- /* Paging disabled or PV: l3 is at the start of a page */
+ /* PV guest: l3 is at the start of a page */
guest_idx = 0;
// Ignore the low 2 bits of guest_idx -- they are really just
if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
{
gl2gfn = guest_l3e_get_gfn(gl3e[i]);
- gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
+ gl2mfn = gfn_to_mfn(d, gl2gfn);
flush |= sh_remove_write_access(v, gl2mfn, 2, 0);
}
}
if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
{
gl2gfn = guest_l3e_get_gfn(gl3e[i]);
- gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
+ gl2mfn = gfn_to_mfn(d, gl2gfn);
sh_set_toplevel_shadow(v, i, gl2mfn, (i == 3)
? SH_type_l2h_shadow
: SH_type_l2_shadow);
}
}
#endif
- mfn = vcpu_gfn_to_mfn(v, gfn);
+ mfn = gfn_to_mfn(v->domain, gfn);
errcode = PFEC_write_access;
if ( !(flags & _PAGE_PRESENT) )
!= PGT_writable_page )
return _mfn(gfn_x(gfn)); /* This is a paging-disabled shadow */
else
- return gfn_to_mfn(v->domain, gfn_x(gfn));
+ return gfn_to_mfn(v->domain, gfn);
}